<template>
  <el-table
    :border="border"
    :stripe="stripe"
    :data="baseTableInfo.data"
    :max-height="maxHeight"
    :cell-style="cellStyle"
    :header-cell-style="headerCellStyle"
    :span-method="spanMethod"
  >
    <el-table-column
      v-for="(col, index) in baseTableInfo.columns"
      :key="index"
      :label="col.label"
      :prop="col.prop"
      :width="col.cellWidth"
      :min-width="col.cellMinWidth"
      :align="col.cellAlign"
      :fixed="
        fixedLeftCols && fixedLeftCols.indexOf(index) >= 0 ? 'left' : false
      "
    >
      <template v-if="col.labelSlot === leftTopThSlot" #header>
        <TableThGroup
          v-if="leftTopLabel"
          :leftLabel="leftTopLabel[0]"
          :rightLabel="leftTopLabel[1]"
        ></TableThGroup>
        <span v-else>{{ baseTableInfo.columns[0].label }}</span>
      </template>
      <template #default="scope">
        <slot
          v-if="scope.row.valueSlot"
          :name="scope.row.valueSlot"
          v-bind="scope"
        ></slot>
        <template v-else>
          {{ cellFormatter(scope.row, col) }}
        </template>
      </template>
    </el-table-column>
  </el-table>
</template>

<script setup name="TableReport">
import { computed, inject } from 'vue'
import { thStyle, tdStyle, borderColor } from './style'
import { transformReportData } from './util'
/**
 * 此表格组件用于第一列与第一行都为标题的场景
 *
 * data: [{year: "2001", amount: 100}, {year: "2002", amount: 200}]
 * config 每行的配置信息，默认将第一行设置为标题，其他行的第一个单元格显示为标题
 *     * { label: "报表期", prop: "year" } 最普通的行
 *     * { label: "将净利润调整为经营活动的现金流量", isRowHeader: true } 整行为标题，无数据
 *     * { valueSlot: "dateValue" } 可使用插槽，重写内容元素，接收el-table的scope参数
 *     * { label: "金额", prop: "amount", formatter: (row, col, cellValue) => {} } 对值格式化
 *     * { label: "金额", prop: "amount", labelStyle: { textIntend: "20px" }, } 对label设置样式
 */
const props = defineProps({
  data: Array,
  config: Array,
  border: {
    type: Boolean,
    default: true,
  },
  stripe: {
    type: Boolean,
    default: false,
  },
  // 表格最大高度
  maxHeight: [Number, String],
  // 所有单元格的对齐方式
  cellAlign: String,
  // 所有单元格的宽度
  cellWidth: [Number, String],
  // 所有单元格的最小宽度
  cellMinWidth: [Number, String],
  // 第一列标题单元格的对齐方式，可覆盖cellAlign。
  labelCellAlign: String,
  // 第一列标题单元格的宽度，可覆盖cellWidth。
  labelCellWidth: [Number, String],
  // 第一列标题单元格的最小宽度，可覆盖cellMinWidth。
  labelCellMinWidth: [Number, String],
  // 左侧固定的列的序号
  fixedLeftCols: Array,
  // 对角label的文案，有此值时会覆盖本身的label
  leftTopLabel: Array,
  // 对行标题label的定义，一般需要传入
  thLabelFn: {
    type: Function,
    default: (dataCol, index) => `th${index}`,
  },
  // 对行标题prop的定义，可使用默认的
  thPropFn: {
    type: Function,
    default: (dataCol, index) => `th${index}`,
  },
})

const emptyCellText = inject('emptyCellText')

// 设置左上角标题单元格的插槽
const leftTopThSlot = 'leftTopTh'

const baseTableInfo = computed(() => {
  const { data, columns } = transformReportData({
    data: props.data,
    config: props.config,
    thLabelFn: props.thLabelFn,
    thPropFn: props.thPropFn,
  })

  columns.forEach((col) => {
    // 设置列的样式属性
    if (col.prop !== 'th0') {
      col.cellAlign = props.cellAlign
      col.cellWidth = props.cellWidth
      col.cellMinWidth = props.cellMinWidth
    } else {
      col.cellAlign = props.labelCellAlign || props.cellAlign
      col.cellWidth = props.labelCellWidth || props.cellWidth
      col.cellMinWidth = props.labelCellMinWidth || props.cellMinWidth
    }
  })

  // 设置左上角标题单元格的插槽
  columns[0].labelSlot = leftTopThSlot

  return {
    data,
    columns,
  }
})

function cellFormatter(row, column) {
  const cellValue = row?.formatter
    ? row.formatter(row, column, row[column.prop])
    : row[column.prop]
  return cellValue === null || cellValue === undefined || cellValue === ''
    ? emptyCellText
    : cellValue
}

function headerCellStyle() {
  return thStyle
}

function cellStyle({ row, column, rowIndex, columnIndex }) {
  if (row.__isRowHeader__) {
    // 属于单行标题时
    return Object.assign(
      {},
      thStyle,
      { textAlign: 'center' },
      row.__labelStyle__
    )
  } else if (baseTableInfo.value?.columns[0].prop === column.property) {
    // 属于第一列时
    if (row.__labelStyle__) {
      return Object.assign({}, thStyle, row.__labelStyle__)
    }
    return thStyle
  } else {
    return tdStyle
  }
}

function spanMethod({ row, column, rowIndex, columnIndex }) {
  if (row.__isRowHeader__) {
    if (columnIndex === 0) {
      return [1, baseTableInfo.value?.columns?.length]
    } else {
      return [0, 0]
    }
  }
}
</script>

<style lang="stylus" scoped>
.table-report
  position relative
  border-top 1px solid v-bind(borderColor)
  .u-header,.u-row
    display flex
    width 100%
  .u-row-header
    text-align center
  .u-cell
    flex 1
    position relative
    padding 11px 20px
    min-width 150px
    line-height 28px
    border-bottom 1px solid v-bind(borderColor)
    border-left 1px solid v-bind(borderColor)
    &:last-child
      border-right 1px solid v-bind(borderColor)
  .u-fixed
    position absolute
    z-index 1
    border-right 1px solid v-bind(borderColor)
</style>
